www.gusucode.com > VC++仿XP免费Prof UIS界面库-源码程序 > VC++仿XP免费Prof UIS界面库-源码程序/code/Src/ExtCmdManager.cpp

    //Download by http://www.NewXing.com
// This is part of the Professional User Interface Suite library.
// Copyright (C) 2001-2004 FOSS Software, Inc.
// All rights reserved.
//
// http://www.prof-uis.com
// http://www.fossware.com
// mailto:foss@fossware.com
//
// This source code can be used, modified and redistributed
// under the terms of the license agreement that is included
// in the Professional User Interface Suite package.
//
// Warranties and Disclaimers:
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND
// INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
// IN NO EVENT WILL FOSS SOFTWARE INC. BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES,
// INCLUDING DAMAGES FOR LOSS OF PROFITS, LOSS OR INACCURACY OF DATA,
// INCURRED BY ANY PERSON FROM SUCH PERSON'S USAGE OF THIS SOFTWARE
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

#include "StdAfx.h"

#if (!defined __ExtCmdManager_H)
	#include <ExtCmdManager.h>
#endif

#if (!defined __EXT_REGISTRY_H)
	#include <ExtRegistry.h>
#endif

#if (!defined __EXT_EXTINTEGRITYCHECKSUM_H)
	#include "ExtIntegrityCheckSum.h"
#endif

#if (!defined __EXT_PAINT_MANAGER_H)
	#include <ExtPaintManager.h>
#endif

#include <../profuisdll/resource.h>

#include <limits.h>

#pragma message("   Prof-UIS is automatically linking with version.lib")
#pragma message("      (Version info support)")
#pragma comment(lib,"version.lib") 

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

static CExtSafeString productsection2regkeypath(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	__EXT_MFC_SAFE_LPCTSTR sSectionNameCompany, // under HKEY_CURRENT_USER\Software
	__EXT_MFC_SAFE_LPCTSTR sSectionNameProduct // under HKEY_CURRENT_USER\Software\%sSectionNameCompany%
	)
{
	return CExtCmdManager::GetSubSystemRegKeyPath(
		__PROF_UIS_REG_COMMAND_MANAGER,
		sProfileName,
		sSectionNameCompany,
		sSectionNameProduct
		);
}

static bool fileobj_to_registry(
	CFile & _file,
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	__EXT_MFC_SAFE_LPCTSTR sSectionNameCompany, // under HKEY_CURRENT_USER\Software
	__EXT_MFC_SAFE_LPCTSTR sSectionNameProduct // under HKEY_CURRENT_USER\Software\%sSectionNameCompany%
	)
{
	ASSERT( sProfileName != NULL );
	ASSERT( sSectionNameCompany != NULL );
	ASSERT( sSectionNameProduct != NULL );
CExtSafeString sRegKeyPath =
		productsection2regkeypath(
			sProfileName,
			sSectionNameCompany,
			sSectionNameProduct
			);

	return CExtCmdManager::FileObjToRegistry( _file, sRegKeyPath );
}

static bool fileobj_from_registry(
	CFile & _file,
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	__EXT_MFC_SAFE_LPCTSTR sSectionNameCompany, // under HKEY_CURRENT_USER\Software
	__EXT_MFC_SAFE_LPCTSTR sSectionNameProduct // under HKEY_CURRENT_USER\Software\%sSectionNameCompany%
	)
{
	ASSERT( sProfileName != NULL );
	ASSERT( sSectionNameCompany != NULL );
	ASSERT( sSectionNameProduct != NULL );
	ASSERT( _file.GetLength() == 0 );
CExtSafeString sRegKeyPath =
		productsection2regkeypath(
				sProfileName,
			sSectionNameCompany,
			sSectionNameProduct
			);
	return CExtCmdManager::FileObjFromRegistry( _file, sRegKeyPath );
}

/////////////////////////////////////////////////////////////////////////////
// CExtCmdItem
// command item class

#define __MAX_TOTAL_TICK_COUNT (UINT_MAX-1)
#define __DECREASE_TICK_COUNT_BY_REF(_REF_) (_REF_) /= 2

CExtCmdItem::CExtCmdItem(
	UINT nCmdID // = IDC_STATIC
	)
	: m_pProfile( NULL )
	, m_nCmdID( nCmdID )
	, m_dwStateFlags( STATE_ENABLED )
	, m_nIconIdx( -1 )
	, m_sMenuText( _T("") )
	, m_sToolbarText( _T("") )
	, m_sTipTool( _T("") )
	, m_sTipStatus( _T("") )
	, m_sAccelText( _T("") )
	, m_nUsageTickCount( 0 )
	, m_nLParamUserData( 0L )
#if (!defined __EXT_MFC_NO_BUILTIN_TEXTFIELD)
	, m_nTextFieldWidth( 100 ) // __EXT_MENU_DEF_INPLACE_EDIT_WIDTH
	, m_nDropDownWidth( -2 ) // (-1) - auto calc, (-2) - same as button area
	, m_nDropDownHeightMax( 250 )
#endif // (!defined __EXT_MFC_NO_BUILTIN_TEXTFIELD)
{
}

CExtCmdItem::CExtCmdItem( const CExtCmdItem & other )
	: m_pProfile( NULL )
	, m_nCmdID( (UINT)IDC_STATIC )
	, m_dwStateFlags( STATE_ENABLED )
	, m_nIconIdx( -1 )
	, m_sMenuText( _T("") )
	, m_sToolbarText( _T("") )
	, m_sTipTool( _T("") )
	, m_sTipStatus( _T("") )
	, m_sAccelText( _T("") )
	, m_nUsageTickCount( 0 )
	, m_nLParamUserData( 0L )
#if (!defined __EXT_MFC_NO_BUILTIN_TEXTFIELD)
	, m_nTextFieldWidth( 100 ) // __EXT_MENU_DEF_INPLACE_EDIT_WIDTH
	, m_nDropDownWidth( -2 ) // (-1) - auto calc, (-2) - same as button area
	, m_nDropDownHeightMax( 250 )
#endif // (!defined __EXT_MFC_NO_BUILTIN_TEXTFIELD)
{
	CExtCmdItem::AssignFromOther(other);
}

CExtCmdItem::~CExtCmdItem()
{
}

CExtCmdItem & CExtCmdItem::operator=( const CExtCmdItem & other )
{
	AssignFromOther(other);
	return *this;
}

void CExtCmdItem::AssignFromOther( const CExtCmdItem & other )
{
LPVOID lpvThis = (LPVOID)this;
LPVOID lpvOther = (LPVOID)(&other);
	if( lpvThis == lpvOther )
		return;
	m_pProfile = other.m_pProfile;
	m_nCmdID = other.m_nCmdID;
	m_dwStateFlags = other.m_dwStateFlags;
	m_nIconIdx = other.m_nIconIdx;
	m_sMenuText = other.m_sMenuText,
	m_sToolbarText = other.m_sToolbarText,
	m_sTipTool = other.m_sTipTool;
	m_sTipStatus = other.m_sTipStatus;
	m_sAccelText = other.m_sAccelText;
	m_nUsageTickCount = other.m_nUsageTickCount;
	m_nLParamUserData = other.m_nLParamUserData;
#if (!defined __EXT_MFC_NO_BUILTIN_TEXTFIELD)
	m_nTextFieldWidth = other.m_nTextFieldWidth;
	m_nDropDownWidth = other.m_nDropDownWidth; // (-1) - auto calc, (-2) - same as button area
	m_nDropDownHeightMax = other.m_nDropDownHeightMax;
#endif // (!defined __EXT_MFC_NO_BUILTIN_TEXTFIELD)
}

void CExtCmdItem::ReplaceFromOtherNonEmpty( const CExtCmdItem & other )
{
LPVOID lpvThis = (LPVOID)this;
LPVOID lpvOther = (LPVOID)(&other);
	if( lpvThis == lpvOther )
		return;
//	ASSERT( m_pProfile == other.m_pProfile );
//	ASSERT( m_nCmdID == other.m_nCmdID );
//	m_dwStateFlags = other.m_dwStateFlags;
	if( other.m_nIconIdx >= 0 )
		m_nIconIdx = other.m_nIconIdx;
	if( !other.m_sMenuText.IsEmpty() )
		m_sMenuText = other.m_sMenuText;
	if( !other.m_sToolbarText.IsEmpty() )
		m_sToolbarText = other.m_sToolbarText;
	if( !other.m_sTipTool.IsEmpty() )
		m_sTipTool = other.m_sTipTool;
	if( !other.m_sTipStatus.IsEmpty() )
		m_sTipStatus = other.m_sTipStatus;
	if( !other.m_sAccelText.IsEmpty() )
		m_sAccelText = other.m_sAccelText;
//	m_nUsageTickCount = other.m_nUsageTickCount;
//	m_nLParamUserData = other.m_nLParamUserData;
}

void CExtCmdItem::UpdateMoreExact( const CExtCmdItem & other )
{
LPVOID lpvThis = (LPVOID)this;
LPVOID lpvOther = (LPVOID)(&other);
	if( lpvThis == lpvOther )
		return;
//	ASSERT( m_pProfile == other.m_pProfile );
//	ASSERT( m_nCmdID == other.m_nCmdID );
//	m_dwStateFlags = other.m_dwStateFlags;
	if( m_nIconIdx < 0 )
		m_nIconIdx = other.m_nIconIdx;
	if( m_sMenuText.IsEmpty() )
		m_sMenuText = other.m_sMenuText;
	if( m_sTipTool.IsEmpty() )
		m_sTipTool = other.m_sTipTool;
	if( m_sTipStatus.IsEmpty() )
		m_sTipStatus = other.m_sTipStatus;
	if( m_sAccelText.IsEmpty() )
		m_sAccelText = other.m_sAccelText;
//	m_nUsageTickCount = other.m_nUsageTickCount;
//	m_nLParamUserData = other.m_nLParamUserData;
}

bool CExtCmdItem::StateIsBasic() const
{
	if( CExtCmdManager::IsForceBasicCommand(m_nCmdID) )
		return true;
	if( CExtCmdManager::IsForceRarelyCommand(m_nCmdID) )
		return false;
bool bBasic =
		(m_dwStateFlags&STATE_BASICCMDPROP) ? true : false;
	return bBasic;
}

bool CExtCmdItem::StateIsRarelyUsed() const
{
	if( StateIsBasic() )
		return false;
UINT nUsagePercent = GetUsagePercent();
	ASSERT( m_pProfile != NULL );
	return
		(nUsagePercent < m_pProfile->m_nRarelyPercent) ?
			true : false;
}

bool CExtCmdItem::StateIsForceRarely() const
{
	if( CExtCmdManager::IsForceRarelyCommand(m_nCmdID) )
		return true;
	if( CExtCmdManager::IsForceBasicCommand(m_nCmdID) )
		return false;
bool bForceRarely =
		(m_dwStateFlags&STATE_FORCE_RARELY) ? true : false;
	return bForceRarely;
}

void CExtCmdItem::TipsClean()
{
	m_sTipTool = _T("");
	m_sTipStatus = _T("");
}

bool CExtCmdItem::TipsLoad()
{
	TipsClean();
	if( !CExtCmdManager::IsCommand(m_nCmdID) )
	{
		ASSERT( FALSE );
		return false;
	}
CExtSafeString sText;
	if( !sText.LoadString(m_nCmdID) )
		return false;
	sText.Replace( _T("\t"), _T(" ") );
	sText.Replace( _T("\r"), _T("") );
	sText.TrimLeft();
	sText.TrimRight();
	if( sText.IsEmpty() )
		return false;
int nSep = sText.ReverseFind('\n');
	if( nSep < 0 )
	{
		//m_sTipTool = sText; // (- v.2.23)
		m_sTipStatus = sText; // (+ v.2.23)
		return true;
	}
int nLen = sText.GetLength();
	m_sTipTool = sText.Right( nLen - nSep );
	m_sTipTool.TrimLeft();
	m_sTipTool.TrimRight();
	m_sTipStatus = sText.Left( nSep );
	m_sTipStatus.TrimLeft();
	m_sTipStatus.TrimRight();
	return true;
}

bool CExtCmdItem::DoUpdateCmdUI(
	CCmdTarget * pCmdTarget,
	UINT nIndex // = 0
	)
{
	ASSERT( pCmdTarget != NULL );
CExtCmdItemUI cmd_ui( this );
	if( CExtCmdManager::IsCommandNeedsSpecUpdate(m_nCmdID) )
	{
		cmd_ui.Enable(TRUE);
		return true;
	} // if( CExtCmdManager::IsCommandNeedsSpecUpdate(m_nCmdID) )
	else
	{
		cmd_ui.m_nIndex = nIndex;
		BOOL bRetVal =
			cmd_ui.DoUpdate(
			pCmdTarget,
			CExtCmdManager::g_bDisableCmdIfNoHandler ?
				TRUE : FALSE
			);
		return bRetVal ? true : false;
	} // else from if( CExtCmdManager::IsCommandNeedsSpecUpdate(m_nCmdID) )
}

bool CExtCmdItem::Deliver(
	HWND hWndCmdTarget,
	bool bSend // = false
	)
{
	if( hWndCmdTarget == NULL )
		return false;
	IncrementUsageCount();
	ASSERT( ::IsWindow( hWndCmdTarget ) );
	ASSERT( CExtCmdManager::IsCommand(m_nCmdID) );
UINT nMsg = WM_COMMAND;
LPARAM lParam = 0;
	if( CExtCmdManager::IsSystemCommand(m_nCmdID) )
	{ // if we need WM_SYSCOMMAND
		nMsg = WM_SYSCOMMAND;
		POINT point = { 0, 0 };
		::GetCursorPos( &point );
		lParam =
			MAKELONG(
				point.x,
				point.y
				);
	} // if we need WM_SYSCOMMAND
	if( bSend )
	{
		if( !::SendMessage(
				hWndCmdTarget,
				nMsg,
				m_nCmdID,
				lParam
				)
			)
		{
			//ASSERT( FALSE );
			return false;
		}
	} // if( bSend )
	else
	{
		if( !::PostMessage(
				hWndCmdTarget,
				nMsg,
				m_nCmdID,
				lParam
				)
			)
		{
			ASSERT( FALSE );
			return false;
		}
	} // else from  if( bSend )
	return true;
}

bool CExtCmdItem::Deliver(
	CWnd * pWndCmdTarget,
	bool bSend // = false
	)
{
	ASSERT_VALID( pWndCmdTarget );
	return
		Deliver(
			pWndCmdTarget->GetSafeHwnd(),
			bSend
			);
}

bool CExtCmdItem::Deliver(
	CControlBar * pWndCmdSource,
	bool bSend // = false
	)
{
	if( pWndCmdSource == NULL
		|| pWndCmdSource->GetSafeHwnd() == NULL
		)
	{
		ASSERT( FALSE );
		return FALSE;
	}
	ASSERT_VALID( pWndCmdSource );
CWnd * pOwner = pWndCmdSource->GetOwner();
	if( pOwner == NULL )
	{
		ASSERT( FALSE );
		return FALSE;
	}
	ASSERT_VALID( pOwner );
	ASSERT( ! pOwner->IsKindOf(RUNTIME_CLASS(CControlBar)) );
	return
		Deliver(
			pOwner->GetSafeHwnd(),
			bSend
			);
}

UINT CExtCmdItem::GetUsageTickCount() const
{
	return m_nUsageTickCount;
}

UINT CExtCmdItem::GetUsagePercent() const
{
	ASSERT( m_pProfile != NULL );
	if( m_pProfile->m_nTotalTickCount == 0 )
		return 0;
	return
		(m_nUsageTickCount * 100)
		/
		m_pProfile->m_nTotalTickCount
		;
}

void CExtCmdItem::IncrementUsageCount()
{
	if( StateIsBasic()
		|| StateIsForceRarely()
		)
		return;
	ASSERT( m_pProfile != NULL );
	m_nUsageTickCount++;
	m_pProfile->m_nTotalTickCount++;
	AnalyzeGlobalUsageOverflow();
}

void CExtCmdItem::ResetUsageStatistics()
{
	if( StateIsBasic()
		|| StateIsForceRarely()
		)
		return;
	ASSERT( m_pProfile != NULL );
	m_nUsageTickCount = 0;
}

UINT CExtCmdItem::GetProfileTickCount() const
{
	ASSERT( m_pProfile != NULL );
	return m_pProfile->m_nTotalTickCount;
}

UINT CExtCmdItem::GetProfileRarelyPercent() const
{
	ASSERT( m_pProfile != NULL );
	return m_pProfile->m_nRarelyPercent;
}

void CExtCmdItem::SetProfileRarelyPercent(
	UINT nRarelyPercent
	)
{
	ASSERT( nRarelyPercent <= 100 );
	if( nRarelyPercent > 100 )
		nRarelyPercent = 100;
	ASSERT( m_pProfile != NULL );
	m_pProfile->m_nRarelyPercent = nRarelyPercent;
}

void CExtCmdItem::AnalyzeGlobalUsageOverflow()
{
	ASSERT( m_pProfile != NULL );
	if( m_pProfile->m_nTotalTickCount < __MAX_TOTAL_TICK_COUNT )
		return;
	__DECREASE_TICK_COUNT_BY_REF( m_pProfile->m_nTotalTickCount );
POSITION pos = m_pProfile->m_cmds.GetStartPosition();
	for( ; pos != NULL; )
	{
		UINT nCmdID;
		CExtCmdItem * pCmdItem = NULL;
		m_pProfile->m_cmds.GetNextAssoc( pos, nCmdID, pCmdItem );
		ASSERT( pCmdItem != NULL );
		__DECREASE_TICK_COUNT_BY_REF( pCmdItem->m_nUsageTickCount );
	}
}

bool CExtCmdItem::OnQueryStateSerializationNecessity() const
{
	if(		StateIsBasic()
		||	StateIsForceRarely()
		||	StateIsMenubarTemp()
		||	CExtCmdManager::IsSystemCommand( m_nCmdID )
		||	m_nUsageTickCount == 0
		)
		return false;
	return true;
}

void CExtCmdItem::OnSysColorChange()
{
	ASSERT( m_pProfile != NULL );
CExtCmdIcon * pIcon = m_pProfile->CmdGetIconPtr( m_nCmdID );
	if( pIcon != NULL )
		pIcon->SyncSysColors();
}

void CExtCmdItem::OnSettingChange(
	UINT uFlags,
	__EXT_MFC_SAFE_LPCTSTR lpszSection
	)
{
	ASSERT( m_pProfile != NULL );
CExtCmdIcon * pIcon = m_pProfile->CmdGetIconPtr( m_nCmdID );
	if( pIcon != NULL )
		pIcon->OnSettingChange( uFlags, lpszSection );
}

void CExtCmdItem::OnDisplayChange(
	INT nDepthBPP,
	CPoint ptSizes
	)
{
	ASSERT( m_pProfile != NULL );
CExtCmdIcon * pIcon = m_pProfile->CmdGetIconPtr( m_nCmdID );
	if( pIcon != NULL )
		pIcon->OnDisplayChange( nDepthBPP, ptSizes );
}

void CExtCmdItem::OnThemeChanged(
	WPARAM wParam,
	LPARAM lParam
	)
{
	ASSERT( m_pProfile != NULL );
CExtCmdIcon * pIcon = m_pProfile->CmdGetIconPtr( m_nCmdID );
	if( pIcon != NULL )
		pIcon->OnThemeChanged( wParam, lParam );
}

CExtSafeString CExtCmdItem::OnGetToolBarCustomizeName()
{
	return OnGetCustomizeScriptName();
}

CExtSafeString CExtCmdItem::OnGetCustomizeScriptName()
{
	if( !m_sMenuText.IsEmpty() )
		return m_sMenuText;
	if( !m_sTipTool.IsEmpty() )
		return m_sTipTool;
	if( !m_sToolbarText.IsEmpty() )
		return m_sToolbarText;
	return CExtSafeString( _T("") );
}

CExtSafeString CExtCmdItem::OnGetCustomizeCommandDescription()
{
	if( !m_sTipStatus.IsEmpty() )
		return m_sTipStatus;
	return CExtSafeString( _T("") );
}


/////////////////////////////////////////////////////////////////////////////
// CExtCmdItemUI
// command UI update class

CExtCmdItemUI::CExtCmdItemUI(
	CExtCmdItem * pCmd,
	int nIndexMax // = 0
	)
{
	ASSERT( pCmd != NULL );
	m_pCmd = pCmd;
	m_nIndexMax = nIndexMax;
	m_nID = pCmd->m_nCmdID;
	m_pOther = NULL;
}

void CExtCmdItemUI::Enable(
	BOOL bOn // = TRUE
	)
{
	ASSERT( m_pCmd != NULL );
	CCmdUI::m_bEnableChanged = TRUE;
	m_pCmd->StateEnable( bOn ? true : false );
}

void CExtCmdItemUI::SetCheck(
	int nCheck // = 1 // 0, 1 or 2 (indeterminate)
	)
{
	ASSERT( m_pCmd != NULL );
	if( nCheck == 0 || nCheck == 1 )
		m_pCmd->StateSetCheck(
			(nCheck == 0) ? false : true
			);
	else
	{
		ASSERT( nCheck == 2 );
		m_pCmd->StateSetIndeterminate(
			true
			);
	}
}

void CExtCmdItemUI::SetRadio(
	BOOL bOn // = TRUE
	)
{
	ASSERT( m_pCmd != NULL );
	m_pCmd->StateSetRadio( bOn ? true : false );
}

void CExtCmdItemUI::SetText(
	__EXT_MFC_SAFE_LPCTSTR lpszText
	)
{
	ASSERT( m_pCmd != NULL );
	m_pCmd->m_sMenuText = lpszText;
}

/////////////////////////////////////////////////////////////////////////////
// CExtCmdProfile
// command profile class

CExtCmdProfile::CExtCmdProfile(
	__EXT_MFC_SAFE_LPCTSTR sName // = NULL
	)
	: m_sName( (sName == NULL) ? _T("") : sName )
	, m_nRarelyPercent( __MFCEXT_DEF_RARELY_USED_PERCENT )
	, m_nTotalTickCount( 0 )
	, m_nLParamUserData( 0L )
{
}

CExtCmdProfile::CExtCmdProfile(
	const CExtCmdProfile & other
	)
	: m_sName( _T("") )
	, m_nRarelyPercent( __MFCEXT_DEF_RARELY_USED_PERCENT )
	, m_nTotalTickCount( 0 )
	, m_nLParamUserData( 0L )
{
	AssignFromOther( other );
}

CExtCmdProfile::~CExtCmdProfile()
{
	_RemoveAllIconsImpl();
	_RemoveAllCmdsImpl();
}

CExtCmdProfile & CExtCmdProfile::operator=(
	const CExtCmdProfile & other
	)
{
	AssignFromOther( other );
	return *this;
}

void CExtCmdProfile::AssignFromOther(
	const CExtCmdProfile & other
	)
{
LPVOID lpvThis = (LPVOID)this;
LPVOID lpvOther = (LPVOID)(&other);
	if( lpvThis == lpvOther )
		return;
	m_sName = other.m_sName;
	m_nRarelyPercent = other.m_nRarelyPercent;
	m_nTotalTickCount = other.m_nTotalTickCount;
	m_nLParamUserData = other.m_nLParamUserData;

	_RemoveAllCmdsImpl();
POSITION pos = other.m_cmds.GetStartPosition();
	for( ; pos != NULL; )
	{
		UINT nCmdID;
		CExtCmdItem * pCmdItem = NULL;
		other.m_cmds.GetNextAssoc( pos, nCmdID, pCmdItem );
		ASSERT( pCmdItem != NULL );
		m_cmds[ nCmdID  ] = OnCreateCmdItem( *pCmdItem );
		ASSERT( m_cmds[ nCmdID  ] != NULL );
	}

	_RemoveAllIconsImpl();
	for(	int iIcon = 0;
			iIcon < other.m_icons.GetSize();
			iIcon++
			)
	{
		CExtCmdIcon * pIcon = other.m_icons[iIcon];
		ASSERT( pIcon != NULL );
		m_icons.Add( new CExtCmdIcon( *pIcon ) );
	}
}

void CExtCmdProfile::_RemoveAllCmdsImpl()
{
POSITION pos = m_cmds.GetStartPosition();
	for( ; pos != NULL; )
	{
		UINT nCmdID;
		CExtCmdItem * pCmdItem = NULL;
		m_cmds.GetNextAssoc( pos, nCmdID, pCmdItem );
		ASSERT( pCmdItem != NULL );
		delete pCmdItem;
	}
	m_cmds.RemoveAll();
}

void CExtCmdProfile::_RemoveAllIconsImpl()
{
	for( INT iIcon = 0; iIcon < m_icons.GetSize(); iIcon++ )
	{
		CExtCmdIcon * pIcon = m_icons[iIcon];
		ASSERT( pIcon != NULL );
		delete pIcon;
	}
	m_icons.RemoveAll();
}

CExtCmdItem * CExtCmdProfile::OnCreateCmdItem( const CExtCmdItem & _cmd )
{
	return new CExtCmdItem( _cmd );
}

bool CExtCmdProfile::CmdSetup(
	const CExtCmdItem & _cmd,
	bool bReplaceOld, // = false // but force set images anywhere if was empty
	bool * pbWasAddedNew // = NULL
	)
{
	if( pbWasAddedNew != NULL )
		*pbWasAddedNew = false;
	if( !CExtCmdManager::IsCommand(_cmd.m_nCmdID) )
	{
		ASSERT(FALSE);
		return false;
	}

CExtCmdItem * pCmdItem = NULL;
BOOL bExist =
		m_cmds.Lookup( _cmd.m_nCmdID, pCmdItem );
	if( !bExist )
	{
		pCmdItem = OnCreateCmdItem( _cmd );
		ASSERT( pCmdItem != NULL );
		pCmdItem->m_pProfile = this;
		m_cmds.SetAt( _cmd.m_nCmdID, pCmdItem );
		if( pbWasAddedNew != NULL )
			*pbWasAddedNew = true;
		return true;
	} // if( !bExist )
	ASSERT( pCmdItem != NULL );
	ASSERT( pCmdItem->m_pProfile == this );
	if( bReplaceOld )
		pCmdItem->ReplaceFromOtherNonEmpty( _cmd ); // (+ v.2.22)
	else
		pCmdItem->UpdateMoreExact( _cmd );

	return true;
}

bool CExtCmdProfile::CmdRemove(
	UINT nCmdID,
	bool * pbWasRemoved // = NULL
	)
{
	if( pbWasRemoved != NULL )
		*pbWasRemoved = false;
	if( !CExtCmdManager::IsCommand(nCmdID) )
	{
		ASSERT(FALSE);
		return false;
	}

CExtCmdItem * pCmdItem = NULL;
BOOL bExist =
		m_cmds.Lookup( nCmdID, pCmdItem );
	if( !bExist )
		return true;
	ASSERT( pCmdItem != NULL );
	delete pCmdItem;
	m_cmds.RemoveKey( nCmdID );
	if( pbWasRemoved != NULL )
		*pbWasRemoved = true;
	return true;
}

void CExtCmdProfile::CmdRemoveByMask(
	DWORD dwMask,
	bool bAllBitsOnly // = false
	)
{
POSITION pos = m_cmds.GetStartPosition();
	for( ; pos != NULL; )
	{
		UINT nCmdID;
		CExtCmdItem * pCmdItem = NULL;
		m_cmds.GetNextAssoc( pos, nCmdID, pCmdItem );
		ASSERT( pCmdItem != NULL );
		DWORD dwTest =
			pCmdItem->m_dwStateFlags & dwMask;
		if( dwTest == 0 )
			continue;
		if( bAllBitsOnly && dwTest != dwMask )
			continue;
		delete pCmdItem;
		m_cmds.RemoveKey( nCmdID );
	}
}

CExtCmdItem * CExtCmdProfile::CmdAllocPtr(
	UINT nCmdID // = 0 // 0 means any free in avail range
	)
{
	if( nCmdID != 0 && CmdIsRegistered(nCmdID) )
		return NULL;
	if( nCmdID == 0 )
	{ // find free ID for new command
		nCmdID = 65534;
		if( !m_cmds.IsEmpty() )
		{
			while( true )
			{
				CExtCmdItem * pCmdItem = NULL;
				BOOL bExist =
					m_cmds.Lookup( nCmdID, pCmdItem );
				if( bExist )
				{
					ASSERT( pCmdItem != NULL );
					nCmdID --;
					if( nCmdID == 0 )
					{
						ASSERT( FALSE );
						return NULL;
					}
					continue;
				}
				ASSERT( CExtCmdManager::IsCommand(nCmdID) );
				break;
			} // while( true )
		} // if( !m_cmds.IsEmpty() )
	} // find free ID for new command
	ASSERT( !CmdIsRegistered(nCmdID) );
CExtCmdItem _cmd(nCmdID);
	if( !CmdSetup(_cmd) )
		return NULL;
CExtCmdItem * pCmdItem = CmdGetPtr(nCmdID);
	ASSERT( pCmdItem != NULL );
	ASSERT( pCmdItem->m_nCmdID == nCmdID );
	return pCmdItem;
}

CExtCmdItem * CExtCmdProfile::CmdGetPtr(
	UINT nCmdID
	)
{
	if( !CExtCmdManager::IsCommand(nCmdID) )
		return NULL;
CExtCmdItem * pCmdItem = NULL;
BOOL bExist =
		m_cmds.Lookup( nCmdID, pCmdItem );
	if( !bExist )
		return NULL;
	ASSERT( pCmdItem != NULL );
	return pCmdItem;
}

bool CExtCmdProfile::CmdSetIcon(
	UINT nCmdID,
	const CExtCmdIcon * pCmdIcon,
	bool bUseCmdIconObject
	)
{
	if( !CExtCmdManager::IsCommand(nCmdID) )
	{
		ASSERT(FALSE);
		return false;
	}
	if(		pCmdIcon != NULL
		&&	pCmdIcon->IsEmpty()
		)
	{
		if( bUseCmdIconObject )
			delete pCmdIcon;
		pCmdIcon = NULL;
	}
CExtCmdItem * pCmdItem = NULL;
BOOL bExist =
		m_cmds.Lookup( nCmdID, pCmdItem );
	if( !bExist )
		return NULL;
	if( pCmdIcon == NULL )
	{ // if remove icon query
		if( pCmdItem->m_nIconIdx < 0 )
			return true;
		ASSERT( pCmdItem->m_nIconIdx < m_icons.GetSize() );
		CExtCmdIcon * pIcon = m_icons[ pCmdItem->m_nIconIdx ];
		ASSERT( pIcon != NULL );
		delete pIcon;
		m_icons.RemoveAt( pCmdItem->m_nIconIdx, 1 ); // 2.23 fix
		POSITION pos = m_cmds.GetStartPosition();
		ASSERT( pos != NULL );
		for( ; pos != NULL; )
		{
			CExtCmdItem * pCmdItemWalk = NULL;
			UINT nCmdIDWalk = (UINT)IDC_STATIC;
			m_cmds.GetNextAssoc( pos, nCmdIDWalk, pCmdItemWalk );
			ASSERT( pCmdItemWalk != NULL );
			ASSERT( nCmdIDWalk == pCmdItemWalk->m_nCmdID );
			if( pCmdItemWalk == pCmdItem )
				continue;
			if( pCmdItemWalk->m_nIconIdx < 0 )
				continue;
			ASSERT( pCmdItemWalk->m_nIconIdx < m_icons.GetSize() );
			ASSERT( pCmdItemWalk->m_nIconIdx != pCmdItem->m_nIconIdx );
			if( pCmdItemWalk->m_nIconIdx < pCmdItem->m_nIconIdx )
				continue;
			pCmdItemWalk->m_nIconIdx --;
		} // for( ; pos != NULL; )
		pCmdItem->m_nIconIdx = -1;
		return true;
	} // if remove icon query
	else
	{ // if add/set icon query
		ASSERT( ! pCmdIcon->IsEmpty() );
		if( pCmdItem->m_nIconIdx < 0 )
		{
			if( ! bUseCmdIconObject )
			{
				try
				{
					CExtCmdIcon * pNewCmdIcon =
						new CExtCmdIcon( *pCmdIcon );
					ASSERT( ! pNewCmdIcon->IsEmpty() );
					pCmdIcon = pNewCmdIcon;
				}
				catch( CException * pXept )
				{
					ASSERT( FALSE );
					pXept->Delete();
					return false;
				}
				catch( ... )
				{
					ASSERT( FALSE );
					return false;
				} // catch( ... )
			} // if( ! bUseCmdIconObject )
			pCmdItem->m_nIconIdx = m_icons.GetSize();
			m_icons.Add(
				const_cast < CExtCmdIcon * > ( pCmdIcon )
				);
			ASSERT( (pCmdItem->m_nIconIdx + 1) == m_icons.GetSize() );
		} // if( pCmdItem->m_nIconIdx < 0 )
		else
		{
			ASSERT( pCmdItem->m_nIconIdx < m_icons.GetSize() );
			CExtCmdIcon * pExistingCmdIcon =
				m_icons[ pCmdItem->m_nIconIdx ];
			ASSERT( pExistingCmdIcon != NULL );
			if( bUseCmdIconObject )
			{
				m_icons.SetAt(pCmdItem->m_nIconIdx, (CExtCmdIcon*)pCmdIcon );
				delete pExistingCmdIcon;
			} // if( bUseCmdIconObject )
			else
			{
				(*pExistingCmdIcon) = (*pCmdIcon);
				ASSERT( ! pExistingCmdIcon->IsEmpty() );
			} // else from if( bUseCmdIconObject )
		} // else from if( pCmdItem->m_nIconIdx < 0 )
		return true;
	} // if add/set icon query
}

bool CExtCmdProfile::CmdSetIcon(
	UINT nCmdID,
	const CExtCmdIcon & cmdIcon // if empty - remove
	)
{
	if( cmdIcon.IsEmpty() )
		return CmdSetIcon( nCmdID, (CExtCmdIcon *)NULL, false );
	return CmdSetIcon( nCmdID, &cmdIcon, false );
}

bool CExtCmdProfile::CmdSetIcon(
	UINT nCmdID,
	HBITMAP hBitmap, // if NULL - remove
	COLORREF clrTransparent, // = RGB(0,0,0)
	LPCRECT pRectBitmapSrc // = NULL
	)
{
	if( hBitmap == NULL )
		return CmdSetIcon( nCmdID, ((CExtCmdIcon *)NULL), false );
CExtCmdIcon _icon( hBitmap, clrTransparent, pRectBitmapSrc );
	return CmdSetIcon( nCmdID, &_icon, false );
}

bool CExtCmdProfile::CmdSetIcon(
	UINT nCmdID,
	HICON hIcon, // if NULL - remove
	bool bCopyIcon // = true
	)
{
	if( hIcon == NULL )
		return CmdSetIcon( nCmdID, ((CExtCmdIcon *)NULL), false );
CExtCmdIcon _icon( hIcon, bCopyIcon );
	return CmdSetIcon( nCmdID, &_icon, false );
}

CExtCmdIcon * CExtCmdProfile::CmdGetIconPtr(
	UINT nCmdID
	)
{
	if( !CExtCmdManager::IsCommand(nCmdID) )
	{
		ASSERT(FALSE);
		return NULL;
	}
CExtCmdItem * pCmdItem = NULL;
BOOL bExist =
		m_cmds.Lookup( nCmdID, pCmdItem );
	if( !bExist )
		return NULL;
	ASSERT( pCmdItem != NULL );
	if( pCmdItem->m_nIconIdx < 0 )
		return NULL;
	ASSERT( pCmdItem->m_nIconIdx < m_icons.GetSize() );
CExtCmdIcon * pIcon = m_icons[ pCmdItem->m_nIconIdx ];
	ASSERT( pIcon != NULL );
	ASSERT( !(pIcon->IsEmpty()) );
	return pIcon;
}

bool CExtCmdProfile::CmdIsRegistered(
	UINT nCmdID
	)
{
bool bRegistered =
		(CmdGetPtr(nCmdID) != NULL) ?
			true : false;
	return bRegistered;
}

bool CExtCmdProfile::UpdateFromMenu(
	HMENU hMenu,
	bool bReplaceOld, // = false
	bool bRecursive, // = true
	bool bLoadTips // = true
	)
{
	if( hMenu == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	if( !(::IsMenu(hMenu)) )
	{
		ASSERT( FALSE );
		return false;
	}

int nMenuItemCount = ::GetMenuItemCount(hMenu);
	for(	int nMenuItemIdx=0;
			nMenuItemIdx < nMenuItemCount;
			nMenuItemIdx++
			)
	{ // for all menu level items
		// get the menu item info
		CExtSafeString sMenuText;
		MENUITEMINFO mii;
		::memset( &mii, 0, sizeof(MENUITEMINFO) );
		mii.cbSize = sizeof(MENUITEMINFO);
		mii.fMask =
			MIIM_CHECKMARKS
			|MIIM_DATA
			|MIIM_ID
			|MIIM_STATE
			|MIIM_SUBMENU
			|MIIM_TYPE
			;
		mii.cch = __MAX_UI_ITEM_TEXT;
		mii.dwTypeData =
			sMenuText.GetBuffer(__MAX_UI_ITEM_TEXT);
		ASSERT( mii.dwTypeData != NULL );
		if( mii.dwTypeData == NULL )
		{
			ASSERT( FALSE );
			continue;
		}
		if( !::GetMenuItemInfo(
				hMenu,
				nMenuItemIdx,
				TRUE,
				&mii
				)
			)
		{
			sMenuText.ReleaseBuffer();
			ASSERT( FALSE );
			continue;
		}
		sMenuText.ReleaseBuffer();
		if( (mii.fType & MFT_SEPARATOR) != 0 )
			continue;
		
		// if sub-menu process it
		if( mii.hSubMenu != NULL )
		{
			if( !bRecursive )
				continue;
			VERIFY(
				UpdateFromMenu(
					mii.hSubMenu,
					bReplaceOld,
					true
					)
				);
			continue;
		} // if( mii.hSubMenu != NULL )
		
		// register command
		if( !CExtCmdManager::IsCommand(mii.wID) )
			continue;

		CExtCmdItem _cmd;
		_cmd.m_nCmdID = mii.wID;

		sMenuText.Replace( _T("\n"), _T("") );
		sMenuText.Replace( _T("\r"), _T("") );
		sMenuText.TrimLeft();
		sMenuText.TrimRight();
		if( !sMenuText.IsEmpty() )
		{
			int nSep =
				sMenuText.ReverseFind( _T('\t') );
			if( nSep >= 0 )
			{
				int nLen = sMenuText.GetLength();
				_cmd.m_sAccelText = sMenuText.Right( nLen - nSep );
				_cmd.m_sAccelText.TrimLeft();
				_cmd.m_sAccelText.TrimRight();
				_cmd.m_sMenuText = sMenuText.Left( nSep );
				_cmd.m_sMenuText.TrimLeft();
				_cmd.m_sMenuText.TrimRight();
			}
			else
				_cmd.m_sMenuText = sMenuText;
		} // if( !sMenuText.IsEmpty() )

		if( bLoadTips )
			_cmd.TipsLoad();

		VERIFY( CmdSetup(_cmd,bReplaceOld) );
	} // for all menu level items

	return true;
}

bool CExtCmdProfile::UpdateFromMenu(
	UINT nResourceID,
	bool bReplaceOld, // = false
	bool bLoadTips // = true
	)
{
CMenu menu;
	if( !menu.LoadMenu(nResourceID) )
	{
		ASSERT(FALSE);
		return false;
	}
	return
		UpdateFromMenu(
			menu.GetSafeHmenu(),
			bReplaceOld,
			true, // bRecursive
			bLoadTips
			);
}

CExtCmdProfile::MFC_TOOLBAR_LOADER::MFC_TOOLBAR_LOADER(
	HINSTANCE hInstResourceCommands,
	HRSRC hRsrcCommands,
	HINSTANCE hInstResourceBitmap,
	HRSRC hRsrcCommandsBitmap,
	COLORREF clrBmpTransparent // = RGB(192,192,192)
	)
	: m_pCommands( NULL )
	, m_pButtons( NULL )
	, m_nCountCommands( 0 )
	, m_nCountButtons( 0 )
	, m_clrBmpTransparent( clrBmpTransparent )
	, m_sizeButton( 0, 0 )
	, m_nVersion( 0 )
{
	ASSERT( hInstResourceCommands != NULL );
	ASSERT( hRsrcCommands != NULL );
	ASSERT( hInstResourceBitmap != NULL );
	ASSERT( hRsrcCommandsBitmap != NULL );

HBITMAP hBitmap =
		CExtPaintManager::stat_LoadBitmapResource(
			hInstResourceBitmap,
			hRsrcCommandsBitmap
			);
	if( hBitmap == NULL )
	{
		ASSERT( FALSE );
		return;
	}
	m_bmp.Attach( hBitmap );
#ifdef _DEBUG
BITMAP _bmpInfo;
	::memset( &_bmpInfo, 0, sizeof(BITMAP) );
	::GetObject( hBitmap, sizeof(BITMAP), &_bmpInfo );
	ASSERT( _bmpInfo.bmWidth > 0 && _bmpInfo.bmHeight > 0 );
#endif // _DEBUG

HGLOBAL hGlobalResourceCommands =
		::LoadResource(
			hInstResourceCommands,
			hRsrcCommands
			);
	ASSERT( hGlobalResourceCommands != NULL );
	if( hGlobalResourceCommands == NULL )
		return;
	LP_MFC_TOOLBAR_RESOURCE_DATA pData =
		(LP_MFC_TOOLBAR_RESOURCE_DATA)
			::LockResource( hGlobalResourceCommands );
	if( pData == NULL )
		return;
	m_nCountCommands = (INT)pData->wItemCount;
	ASSERT( m_nCountCommands > 0 );
	m_nVersion = pData->wVersion;
	m_pCommands = new UINT[ m_nCountCommands ];
	m_nCountButtons = 0;
	for(	INT nCommandIdx = 0;
			nCommandIdx < m_nCountCommands;
			nCommandIdx++
			)
	{
		m_pCommands[nCommandIdx] = pData->items()[nCommandIdx];
		if( m_pCommands[nCommandIdx] != ID_SEPARATOR )
			m_nCountButtons++;
	}
	ASSERT( m_nCountButtons > 0 );
	m_pButtons =  new UINT[ m_nCountButtons ];
INT nButtonIdx = 0;
	for(	nCommandIdx = 0;
			nCommandIdx < m_nCountCommands;
			nCommandIdx++
			)
	{
		if( m_pCommands[nCommandIdx] == ID_SEPARATOR )
			continue;
		ASSERT( nButtonIdx < m_nCountButtons );
		m_pButtons[ nButtonIdx ] = m_pCommands[nCommandIdx];
		nButtonIdx++;
		if( nButtonIdx == m_nCountButtons )
			break;
	}

	ASSERT( pData->wWidth > 0 && pData->wHeight > 0 );

	m_sizeButton.cx = (INT)pData->wWidth;
	m_sizeButton.cy = (INT)pData->wHeight;
	ASSERT( _bmpInfo.bmWidth >= ( LONG(m_sizeButton.cx) * LONG(m_nCountButtons) ) );
	ASSERT( _bmpInfo.bmHeight >= LONG(m_sizeButton.cy) );
	
	::UnlockResource( hGlobalResourceCommands );
	::FreeResource( hGlobalResourceCommands );
}

CExtCmdProfile::MFC_TOOLBAR_LOADER::~MFC_TOOLBAR_LOADER()
{
	if( m_pCommands != NULL )
		delete [] m_pCommands;
	if( m_pButtons != NULL )
		delete [] m_pButtons;
	if( m_bmp.GetSafeHandle() != NULL )
		m_bmp.DeleteObject();
}

WORD CExtCmdProfile::MFC_TOOLBAR_LOADER::GetVersion() const
{
	return m_nVersion;
}

INT CExtCmdProfile::MFC_TOOLBAR_LOADER::IsEmpty() const
{
	return ( m_pCommands == NULL ) ? true : false;
}

INT CExtCmdProfile::MFC_TOOLBAR_LOADER::GetCommandCount() const
{
	if( m_pCommands == NULL )
		return 0;
	ASSERT( m_nCountCommands > 0 );
	ASSERT( m_nCountButtons > 0 );
	ASSERT( m_pButtons != NULL );
	ASSERT( m_bmp.GetSafeHandle() != NULL );
	ASSERT( m_sizeButton.cx > 0 && m_sizeButton.cy > 0 );
	return m_nCountCommands;
}

INT CExtCmdProfile::MFC_TOOLBAR_LOADER::GetButtonCount() const
{
	if( m_pCommands == NULL )
		return 0;
	ASSERT( m_nCountCommands > 0 );
	ASSERT( m_nCountButtons > 0 );
	ASSERT( m_pButtons != NULL );
	ASSERT( m_bmp.GetSafeHandle() != NULL );
	ASSERT( m_sizeButton.cx > 0 && m_sizeButton.cy > 0 );
	return m_nCountButtons;
}

COLORREF CExtCmdProfile::MFC_TOOLBAR_LOADER::GetTransparentColor() const
{
	return m_clrBmpTransparent;
}

UINT CExtCmdProfile::MFC_TOOLBAR_LOADER::GetCommandIdAt( INT nCommandIdx ) const
{
	if( IsEmpty() )
	{
		ASSERT( FALSE );
		return 0;
	}
	ASSERT( m_pCommands != NULL );
	ASSERT( m_nCountCommands != NULL );
	if( nCommandIdx < 0 || nCommandIdx >= m_nCountCommands )
	{
		ASSERT( FALSE );
		return 0;
	}
	return m_pCommands[ nCommandIdx ];
}

UINT CExtCmdProfile::MFC_TOOLBAR_LOADER::GetButtonIdAt( INT nButtonIdx ) const
{
	if( IsEmpty() )
	{
		ASSERT( FALSE );
		return 0;
	}
	ASSERT( m_pButtons != NULL );
	ASSERT( m_nCountButtons != NULL );
	if( nButtonIdx < 0 || nButtonIdx >= m_nCountButtons )
	{
		ASSERT( FALSE );
		return 0;
	}
	return m_pButtons[ nButtonIdx ];
}

UINT CExtCmdProfile::MFC_TOOLBAR_LOADER::ExtractButtonData(
	INT nButtonIdx,
	CExtCmdIcon & icon
	) const
{
	icon.Empty();
	if( IsEmpty() )
	{
		ASSERT( FALSE );
		return 0;
	}
	ASSERT( m_nCountCommands > 0 );
	ASSERT( m_nCountButtons > 0 );
	ASSERT( m_pCommands != NULL );
	ASSERT( m_pButtons != NULL );
	ASSERT( m_bmp.GetSafeHandle() != NULL );
	ASSERT( m_sizeButton.cx > 0 && m_sizeButton.cy > 0 );
	if( nButtonIdx < 0 || nButtonIdx >= m_nCountButtons )
	{
		ASSERT( FALSE );
		return 0;
	}
CPoint ptItem( m_sizeButton.cx * nButtonIdx, 0 );
CRect rcItem( ptItem, m_sizeButton );
	icon.AssignFromHBITMAP(
		(HBITMAP)m_bmp.GetSafeHandle(),
		m_clrBmpTransparent,
		&rcItem
		);
	if( icon.IsEmpty() )
	{
		ASSERT( FALSE );
		return 0;
	}
	return m_pButtons[ nButtonIdx ];
}

void CExtCmdProfile::MFC_TOOLBAR_LOADER::GetCmdArray(
	LPUINT * ppCmdArray,
	LPINT pCmdCount // = NULL
	) const
{
	if( ppCmdArray != NULL )
		(*ppCmdArray) = NULL;
	if( pCmdCount != NULL )
		(*pCmdCount) = m_nCountCommands;
	if( IsEmpty() || ppCmdArray == NULL )
		return;
	ASSERT( m_nCountCommands > 0 );
	ASSERT( m_nCountButtons > 0 );
	ASSERT( m_pCommands != NULL );
	ASSERT( m_pButtons != NULL );
	(*ppCmdArray) = new UINT[ m_nCountCommands ];
	::memcpy(
		(LPVOID)(*ppCmdArray),
		(LPCVOID)m_pCommands,
		m_nCountCommands * sizeof(UINT)
		);
}

bool CExtCmdProfile::UpdateFromToolBar(
	CToolBar & bar,
	bool bReplaceOld, // = false // but force set images anywhere if was empty
	bool bLoadTips // = true
	)
{
	if(		bar.GetSafeHwnd() == NULL
		||	(! ::IsWindow(bar.GetSafeHwnd()))
		)
	{
		ASSERT( FALSE );
		return false;
	}
CImageList * pImageList =
		bar.GetToolBarCtrl().GetImageList();
	if( pImageList == NULL
		|| pImageList->GetSafeHandle() == NULL
		)
	{
		ASSERT( FALSE );
		return false;
	}
int nButtonCount = bar.GetCount();
    for( int nButtonIdx = 0; nButtonIdx < nButtonCount; nButtonIdx++ )
	{
		// get button info
		UINT nCmdID = bar.GetItemID( nButtonIdx ); 
		if( nCmdID == ID_SEPARATOR )
			continue;
		ASSERT( CExtCmdManager::IsCommand( nCmdID ) );

		TBBUTTONINFO tbi;
		::memset( &tbi, 0, sizeof(TBBUTTONINFO) );
		tbi.cbSize = sizeof(TBBUTTONINFO);
		tbi.idCommand = nCmdID;
		tbi.dwMask = TBIF_IMAGE|TBIF_TEXT;
		tbi.cchText = __MAX_UI_ITEM_TEXT;
		CExtSafeString sToolbarText;
		tbi.pszText =
			sToolbarText.GetBuffer(__MAX_UI_ITEM_TEXT);
		ASSERT( tbi.pszText != NULL );
		if( tbi.pszText == NULL )
		{
			ASSERT( FALSE );
			continue;
		}
		if( !bar.GetToolBarCtrl().GetButtonInfo(nCmdID,&tbi) )
		{
			UINT nDummyID,nDummyStyle;
			bar.GetButtonInfo(
				nButtonIdx,
				nDummyID,
				nDummyStyle,
				tbi.iImage
				);
		}
		sToolbarText.ReleaseBuffer();

		// register command
		CExtCmdItem _cmd;
		_cmd.m_nCmdID = nCmdID;
		_cmd.m_sToolbarText = sToolbarText;
		if( bLoadTips )
			_cmd.TipsLoad();
		if( !CmdSetup(_cmd,bReplaceOld) )
		{
			ASSERT(FALSE);
			continue;
		}
		if( tbi.iImage < 0 )
			continue;
		ASSERT( tbi.iImage < pImageList->GetImageCount() );
		CExtCmdItem * pCmdItem = CmdGetPtr(nCmdID);
		ASSERT( pCmdItem != NULL );
		if( pCmdItem->m_nIconIdx >= 0 )
		{
			ASSERT( pCmdItem->m_nIconIdx < m_icons.GetSize() );
			continue;
		}
		HICON hIcon = pImageList->ExtractIcon( tbi.iImage );
		if( hIcon == NULL )
		{
			ASSERT(FALSE);
			continue;
		}
		CExtCmdIcon * pIcon = new CExtCmdIcon;
		pIcon->AssignFromHICON( hIcon, false );
		int nIconIndex = m_icons.Add( pIcon );
		ASSERT( nIconIndex >= 0 );
		pCmdItem->m_nIconIdx = nIconIndex;
	} // for( int nButtonIdx = 0; nButtonIdx < nButtonCount; nButtonIdx++ )
	return true;
}

bool CExtCmdProfile::UpdateFromToolBar(
	__EXT_MFC_SAFE_LPCTSTR strResourceID,
	LPUINT * ppCmdArray, // = NULL
	LPINT pCmdCount, // = NULL
	bool bReplaceOld, // = false // but force set images anywhere if was empty
	bool bLoadTips, // = true
	COLORREF clrBmpTransparent // = RGB(192,192,192)
	)
{
	ASSERT( strResourceID != NULL );
	if( strResourceID == NULL )
		return false;

HINSTANCE hInstResourceCommands =
		::AfxFindResourceHandle(
			strResourceID,
			RT_TOOLBAR
			);
	if( hInstResourceCommands == NULL )
		return false;
HRSRC hRsrcCommands =
		::FindResource(
			hInstResourceCommands,
			strResourceID,
			RT_TOOLBAR
			);
	if( hRsrcCommands == NULL )
		return false;
HINSTANCE hInstResourceBitmap =
		::AfxFindResourceHandle(
			strResourceID,
			RT_BITMAP
			);
	if( hInstResourceBitmap == NULL )
		return false;
HRSRC hRsrcBitmap =
		::FindResource(
			hInstResourceBitmap,
			strResourceID,
			RT_BITMAP
			);
	if( hRsrcBitmap == NULL )
		return false;

MFC_TOOLBAR_LOADER _loader(
		hInstResourceCommands,
		hRsrcCommands,
		hInstResourceBitmap,
		hRsrcBitmap,
		clrBmpTransparent
		);
	if( _loader.IsEmpty() )
		return false;
int nButtonCount = _loader.GetButtonCount();
	ASSERT( nButtonCount > 0 );
    for( int nButtonIdx = 0; nButtonIdx < nButtonCount; nButtonIdx++ )
	{
		CExtCmdIcon * pIcon = new CExtCmdIcon;
		CExtCmdItem _cmd;
		_cmd.m_nCmdID =
			_loader.ExtractButtonData( nButtonIdx, *pIcon );
		if( _cmd.m_nCmdID == 0 || pIcon->IsEmpty() )
		{
			ASSERT( FALSE );
			delete pIcon;
			continue;
		} // if( _cmd.m_nCmdID == 0 || pIcon->IsEmpty() )
		ASSERT( CExtCmdManager::IsCommand( _cmd.m_nCmdID ) );
		if( bLoadTips )
			_cmd.TipsLoad();
		if( !CmdSetup( _cmd, bReplaceOld ) )
		{
			ASSERT(FALSE);
			delete pIcon;
			continue;
		} // if( !CmdSetup( _cmd, bReplaceOld ) )
		CExtCmdItem * pCmdItem = CmdGetPtr( _cmd.m_nCmdID );
		ASSERT( pCmdItem != NULL );
		if( pCmdItem->m_nIconIdx >= 0 )
		{
			ASSERT( pCmdItem->m_nIconIdx < m_icons.GetSize() );
			delete pIcon;
			continue;
		} // if( pCmdItem->m_nIconIdx >= 0 )
		int nIconIndex = m_icons.Add( pIcon );
		ASSERT( nIconIndex >= 0 );
		pCmdItem->m_nIconIdx = nIconIndex;
	} // for( int nButtonIdx = 0; nButtonIdx < nButtonCount; nButtonIdx++ )
	_loader.GetCmdArray( ppCmdArray, pCmdCount );
	return true;
}

bool CExtCmdProfile::SerializeState(
	CArchive & ar
	)
{
bool bRetVal = false;
	try
	{
		CExtSafeString sFriendlyVer;
		DWORD dwApiVer0 = g_CmdManager.GetVersionDWORD( false );
		DWORD dwApiVer1 = g_CmdManager.GetVersionDWORD( true );
		DWORD dwReserved = 0;

		if( ar.IsStoring() )
		{ // store state
			CExtSafeString sTmpBuffer;
			// store version info
			sFriendlyVer.Format(
				_T("Prof-UIS (v. %s) command profile"),
				g_CmdManager.GetVersionString( sTmpBuffer )
				);
			ar << sFriendlyVer;
			ar << dwApiVer0;
			ar << dwApiVer1;
			ar << dwReserved;
			ar << dwReserved;
			ar << dwReserved;
			ar << dwReserved;

			// store command usage information
			ar << m_nTotalTickCount;

			POSITION pos = m_cmds.GetStartPosition();
			for( ; pos != NULL; )
			{
				UINT nCmdID;
				CExtCmdItem * pCmdItem = NULL;
				m_cmds.GetNextAssoc( pos, nCmdID, pCmdItem);
				ASSERT( pCmdItem != NULL );
				if( !pCmdItem->OnQueryStateSerializationNecessity() )
					continue;
				ar << pCmdItem->m_nCmdID;
				ar << pCmdItem->m_nUsageTickCount;
			}

			ar << ((UINT)(0));
		} // store state
		else
		{ // load state
			// load version info
			DWORD dwApiVer0a = 0, dwApiVer1a = 0;
			ar >> sFriendlyVer;
			ar >> dwApiVer0a;
			ar >> dwApiVer1a;
			ar >> dwReserved;
			ar >> dwReserved;
			ar >> dwReserved;
			ar >> dwReserved;
			if( dwApiVer1 != dwApiVer1a )
				return false;

			// load command usage information
			ar >> m_nTotalTickCount;
			for( ; true; )
			{
				UINT nCmdId,nUsageTickCount;
				ar >> nCmdId;
				if( nCmdId == 0 )
					break;
				ar >> nUsageTickCount;
				CExtCmdItem * pCmdItem = CmdGetPtr(nCmdId);
				ASSERT( pCmdItem != NULL );
				ASSERT( !(pCmdItem->StateIsBasic()) );
				ASSERT( !(pCmdItem->StateIsForceRarely()) );
				ASSERT( !(CExtCmdManager::IsSystemCommand(pCmdItem->m_nCmdID)) );
				pCmdItem->m_nUsageTickCount = nUsageTickCount;
			}
		} // load state

		bRetVal = true;
	} // try
	catch( CException * pXept )
	{
		pXept->Delete();
		ASSERT( FALSE );
	} // catch( CException * pXept )
	catch( ... )
	{
		ASSERT( FALSE );
	} // catch( ... )
	return bRetVal;
}

bool CExtCmdProfile::SetBasicCommands(
	UINT * pCommands,
	bool bOn // = true
	)
{
	if( pCommands == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
bool bRetVal = true;
	for(; *pCommands != 0; pCommands++ )
	{
		if( CExtCmdManager::IsSystemCommand( *pCommands ) )
		{
			ASSERT( FALSE );
			bRetVal = false; // we find some error
			continue;
		}
		CExtCmdItem * pCmdItem = CmdGetPtr( *pCommands );
		if( pCmdItem == NULL )
		{
			ASSERT( FALSE );
			bRetVal = false; // we find some error
			continue;
		}
		pCmdItem->StateSetBasic( bOn );
	} // for(; *pCommands != 0; pCommands++ )
	return bRetVal;
}

bool CExtCmdProfile::SerializeState(
	__EXT_MFC_SAFE_LPCTSTR sSectionNameCompany, // under HKEY_CURRENT_USER\Software
	__EXT_MFC_SAFE_LPCTSTR sSectionNameProduct, // under HKEY_CURRENT_USER\Software\%sSectionNameCompany%
	bool bSave
	)
{
	ASSERT( sSectionNameCompany != NULL );
	ASSERT( sSectionNameProduct != NULL );
bool bRetVal = false;
	try
	{
		CMemFile _file;
		if( bSave )
		{
			{ // BLOCK: CArchive usage
				CArchive ar(
					&_file,
					CArchive::store
					);
				if( !SerializeState(ar) )
					return false;
				ar.Flush();
			} // BLOCK: CArchive usage

			// ... write _file to registty
			_file.Seek(0,CFile::begin);
			if( !fileobj_to_registry(
					_file,
					m_sName,
					sSectionNameCompany,
					sSectionNameProduct
					)
				)
				return false;

		} // if( bSave )
		else
		{
			// ... read _file from registty
			if( !fileobj_from_registry(
					_file,
					m_sName,
					sSectionNameCompany,
					sSectionNameProduct
					)
				)
				return false;
			_file.Seek(0,CFile::begin);

			CArchive ar(
				&_file,
				CArchive::load
				);
			if( !SerializeState(ar) )
				return false;
		} // else from if( bSave )

		bRetVal = true;
	} // try
	catch( CException * pXept )
	{
		pXept->Delete();
		ASSERT( FALSE );
	} // catch( CException * pXept )
	catch( ... )
	{
		ASSERT( FALSE );
	} // catch( ... )
	return bRetVal;
}

void CExtCmdProfile::OnSysColorChange()
{
POSITION pos = m_cmds.GetStartPosition();
	for( ; pos != NULL; )
	{
		UINT nCmdID = 0;
		CExtCmdItem * pCmdItem = NULL;
		m_cmds.GetNextAssoc( pos, nCmdID, pCmdItem);
		ASSERT( pCmdItem != NULL );
		pCmdItem->OnSysColorChange();
	} // for( ; pos != NULL; )
}

void CExtCmdProfile::OnSettingChange(
	UINT uFlags,
	__EXT_MFC_SAFE_LPCTSTR lpszSection
	)
{
POSITION pos = m_cmds.GetStartPosition();
	for( ; pos != NULL; )
	{
		UINT nCmdID = 0;
		CExtCmdItem * pCmdItem = NULL;
		m_cmds.GetNextAssoc( pos, nCmdID, pCmdItem);
		ASSERT( pCmdItem != NULL );
		pCmdItem->OnSettingChange( uFlags, lpszSection );
	} // for( ; pos != NULL; )
}

void CExtCmdProfile::OnDisplayChange(
	INT nDepthBPP,
	CPoint ptSizes
	)
{
POSITION pos = m_cmds.GetStartPosition();
	for( ; pos != NULL; )
	{
		UINT nCmdID = 0;
		CExtCmdItem * pCmdItem = NULL;
		m_cmds.GetNextAssoc( pos, nCmdID, pCmdItem);
		ASSERT( pCmdItem != NULL );
		pCmdItem->OnDisplayChange( nDepthBPP, ptSizes );
	} // for( ; pos != NULL; )
}

void CExtCmdProfile::OnThemeChanged(
	WPARAM wParam,
	LPARAM lParam
	)
{
POSITION pos = m_cmds.GetStartPosition();
	for( ; pos != NULL; )
	{
		UINT nCmdID = 0;
		CExtCmdItem * pCmdItem = NULL;
		m_cmds.GetNextAssoc( pos, nCmdID, pCmdItem);
		ASSERT( pCmdItem != NULL );
		pCmdItem->OnThemeChanged( wParam, lParam );
	} // for( ; pos != NULL; )
}

void CExtCmdProfile::ResetUsageStatistics()
{
POSITION pos = m_cmds.GetStartPosition();
	for( ; pos != NULL; )
	{
		UINT nCmdID = 0;
		CExtCmdItem * pCmdItem = NULL;
		m_cmds.GetNextAssoc( pos, nCmdID, pCmdItem);
		ASSERT( pCmdItem != NULL );
		pCmdItem->ResetUsageStatistics();
	}
	m_nTotalTickCount = 0;
}

/////////////////////////////////////////////////////////////////////////////
// CExtCmdManager
// command manager class

CExtCmdManager::CExtCmdManagerAutoPtr g_CmdManager;

volatile DWORD CExtCmdManager::CExtCmdManagerAutoPtr::g_dwVersion = 0;

DWORD CExtCmdManager::CExtCmdManagerAutoPtr::GetVersionDWORD(
	bool bForSerialization // = false
	)
{
#if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)

DWORD dwVersion = 0;
static CCriticalSection scs;
CSingleLock sl( &scs );
BYTE * pByteVerInfo = NULL;
	sl.Lock();
	try
	{
		if( g_dwVersion == 0 )
		{
			HANDLE hModule =
				::GetModuleHandle( __PROF_UIS_MODULE_NAME );
			ASSERT( hModule != NULL );
			TCHAR szFileName[MAX_PATH];
			VERIFY(
				::GetModuleFileName(
					HINSTANCE(hModule),
					szFileName,
					MAX_PATH
					)
				);
			DWORD dwFVIS =
				::GetFileVersionInfoSize(
					szFileName,
					&dwFVIS
					);
			pByteVerInfo = new BYTE[4096];
			::memset( pByteVerInfo, 0, 4096 );
			VERIFY(
				::GetFileVersionInfo(
					szFileName,
					NULL,
					dwFVIS,
					pByteVerInfo
					)
				);
			UINT uNum = 0;
			VS_FIXEDFILEINFO * lpv = NULL;
			VERIFY(
				::VerQueryValue(
					pByteVerInfo,
					_T("\\"),
					((LPVOID*)&lpv),
					&uNum
					)
				);
			ASSERT( lpv != NULL );
			g_dwVersion = 
				 (DWORD(HIWORD(lpv->dwFileVersionMS)&0x0FF)<<24)
				|(DWORD(LOWORD(lpv->dwFileVersionMS)&0x0FF)<<16)
				|(DWORD(HIWORD(lpv->dwFileVersionLS)&0x0FF)<<8)
				|(DWORD(LOWORD(lpv->dwFileVersionLS)&0x0FF))
				;
			if( pByteVerInfo != NULL )
			{
				delete [] pByteVerInfo;
				pByteVerInfo = NULL;
			}
		} // if( g_dwVersion == 0 )
		dwVersion = g_dwVersion;
		if( bForSerialization )
			dwVersion >>= 16;
	} // try
	catch( CException * pXept )
	{
		pXept->Delete();
		ASSERT( FALSE );
	} // catch( CException * pXept )
	catch( ... )
	{
		ASSERT( FALSE );
	} // catch( ... )
	sl.Unlock();
	if( pByteVerInfo != NULL )
		delete [] pByteVerInfo;
	return dwVersion;

#else // #if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)

DWORD dwVersion = __PROF_UIS_VERSION_DWORD;
	if( g_dwVersion == 0 )
	{
		static CCriticalSection scs;
		CSingleLock sl( &scs );
		sl.Lock();
		g_dwVersion = dwVersion;
		sl.Unlock();
	}
	if( bForSerialization )
		dwVersion >>= 16;
	return dwVersion;

#endif // else from #if (defined _AFXDLL && !defined __STATPROFUIS_WITH_DLLMFC__)
}

__EXT_MFC_SAFE_LPCTSTR CExtCmdManager::CExtCmdManagerAutoPtr::GetVersionString(
	CExtSafeString & strBuff,
	__EXT_MFC_SAFE_TCHAR tchrSeparator // = _T('.')
	)
{
DWORD dwVersion = GetVersionDWORD( false );
	ASSERT( dwVersion != 0 );
	strBuff.Format(
		_T("%d%c%d%c%d%c%d"),
		INT( (dwVersion>>24)&0x0FF ),
		tchrSeparator,
		INT( (dwVersion>>16)&0x0FF ),
		tchrSeparator,
		INT( (dwVersion>>8)&0x0FF ),
		tchrSeparator,
		INT( dwVersion&0x0FF )
		);
	return strBuff;
}

CExtCmdManager::CExtCmdManagerAutoPtr::CExtCmdManagerAutoPtr()
{
	m_pCmdManager = new CExtCmdManager;
}

CExtCmdManager::CExtCmdManagerAutoPtr::~CExtCmdManagerAutoPtr()
{
	ASSERT( m_pCmdManager != NULL );
	if( m_pCmdManager != NULL )
	{
		delete m_pCmdManager;
		m_pCmdManager = NULL;
	}
}

CExtCmdManager * CExtCmdManager::CExtCmdManagerAutoPtr::operator->()
{
	ASSERT( m_pCmdManager != NULL );
	return m_pCmdManager;
}

void CExtCmdManager::CExtCmdManagerAutoPtr::OnSysColorChange(
	CWnd * pWndNotifySrc
	)
{
	ASSERT_VALID( pWndNotifySrc );
	ASSERT( pWndNotifySrc->GetSafeHwnd() != NULL && ::IsWindow(pWndNotifySrc->GetSafeHwnd()) );
	ASSERT( m_pCmdManager != NULL );
	if( !g_PaintManager.IsWndUpdateSource(pWndNotifySrc) )
		return;
	m_pCmdManager->OnSysColorChange();
}

void CExtCmdManager::CExtCmdManagerAutoPtr::OnSettingChange(
	CWnd * pWndNotifySrc,
	UINT uFlags,
	__EXT_MFC_SAFE_LPCTSTR lpszSection
	)
{
	ASSERT_VALID( pWndNotifySrc );
	ASSERT( pWndNotifySrc->GetSafeHwnd() != NULL && ::IsWindow(pWndNotifySrc->GetSafeHwnd()) );
	ASSERT( m_pCmdManager != NULL );
	if( !g_PaintManager.IsWndUpdateSource(pWndNotifySrc) )
		return;
	m_pCmdManager->OnSettingChange( uFlags, lpszSection );
}

void CExtCmdManager::CExtCmdManagerAutoPtr::OnDisplayChange(
	CWnd * pWndNotifySrc,
	INT nDepthBPP,
	CPoint ptSizes
	)
{
	ASSERT_VALID( pWndNotifySrc );
	ASSERT( pWndNotifySrc->GetSafeHwnd() != NULL && ::IsWindow(pWndNotifySrc->GetSafeHwnd()) );
	ASSERT( m_pCmdManager != NULL );
	if( !g_PaintManager.IsWndUpdateSource(pWndNotifySrc) )
		return;
	m_pCmdManager->OnDisplayChange( nDepthBPP, ptSizes );
}

void CExtCmdManager::CExtCmdManagerAutoPtr::OnThemeChanged(
	CWnd * pWndNotifySrc,
	WPARAM wParam,
	LPARAM lParam
	)
{
	ASSERT_VALID( pWndNotifySrc );
	ASSERT( pWndNotifySrc->GetSafeHwnd() != NULL && ::IsWindow(pWndNotifySrc->GetSafeHwnd()) );
	ASSERT( m_pCmdManager != NULL );
	if( !g_PaintManager.IsWndUpdateSource(pWndNotifySrc) )
		return;
	m_pCmdManager->OnThemeChanged( wParam, lParam );
}

bool CExtCmdManager::g_bDisableCmdIfNoHandler = true;

CExtCmdManager::CExtCmdManager()
{
	ProfileSetup(
		__EXTMFC_DEF_PROFILE_NAME
		);
}

CExtCmdManager::~CExtCmdManager()
{
	_RemoveAllProfilesImpl();
}

void CExtCmdManager::_RemoveAllProfilesImpl()
{
	POSITION pos = m_profiles.GetStartPosition();
	for( ; pos != NULL; )
	{
		CExtSafeString sProfileName;
		CExtCmdProfile * pProfile = NULL;
		m_profiles.GetNextAssoc( pos, sProfileName, (void *&)pProfile );
		ASSERT( pProfile != NULL );
		delete pProfile;
	} // for( ; pos != NULL; )
	m_profiles.RemoveAll();
	m_profile_wnds.RemoveAll();
}

// setup single profile
bool CExtCmdManager::ProfileSetup(
	__EXT_MFC_SAFE_LPCTSTR sProfileName, //  = NULL
	HWND hProfileWnd, // = NULL
	CExtCmdProfile * pNewProfileInstance // = NULL
	)
{
	if(		sProfileName == NULL
		||	_tcslen( sProfileName ) == 0
		)
		sProfileName = __EXTMFC_DEF_PROFILE_NAME;
	m_cs.Lock();
CExtCmdProfile * pProfile = NULL;
BOOL bExist = m_profiles.Lookup( sProfileName, (void *&)pProfile );
	if( !bExist )
	{
		if( pNewProfileInstance != NULL )
		{
			pProfile = pNewProfileInstance;
			// avoid invalid method usage
			ASSERT( pNewProfileInstance->m_sName == LPCTSTR( sProfileName ) );
		} // if( pNewProfileInstance != NULL )
		else
			pProfile = new CExtCmdProfile( sProfileName );
		m_profiles.SetAt( sProfileName, pProfile );
	} // if( !bExist )
#ifdef _DEBUG
	else
	{
		// avoid leaks when invalid method usage
		ASSERT( pNewProfileInstance == NULL );
	} // else from if( !bExist )
#endif // _DEBUG
	ASSERT( pProfile != NULL );
	ASSERT( pProfile->m_sName == LPCTSTR(sProfileName) );
	m_cs.Unlock();
	if( hProfileWnd != NULL )
		return ProfileWndAdd( sProfileName, hProfileWnd );
	else
		return true;
}

// setup profile window
bool CExtCmdManager::ProfileWndAdd(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	HWND hProfileWnd
	)
{
	ASSERT( hProfileWnd != NULL );
	if( hProfileWnd == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	ASSERT( ::IsWindow(hProfileWnd) );
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
CExtCmdProfile * pProfile2 = NULL;
BOOL bExist = m_profile_wnds.Lookup( hProfileWnd, pProfile2 );
	if( !bExist )
		m_profile_wnds.SetAt( hProfileWnd, pProfile );
#ifdef _DEBUG
	else
	{
		ASSERT( pProfile2 != NULL );
		ASSERT( pProfile2 == pProfile );
	}
#endif // _DEBUG
	m_cs.Unlock();
	return true;
}

// remove profile window
bool CExtCmdManager::ProfileWndRemove(
	HWND hProfileWnd,
	bool bRemoveProfileIfLastHWND, // = false
	bool * p_bProfileWasRemoved // = NULL
	)
{
	ASSERT( hProfileWnd != NULL );
	if( p_bProfileWasRemoved  != NULL )
		*p_bProfileWasRemoved = false;
	if( hProfileWnd == NULL )
		return false;
	ASSERT( ::IsWindow(hProfileWnd) );
	m_cs.Lock();

CExtCmdProfile * pProfile = NULL;
BOOL bExists = m_profile_wnds.Lookup( hProfileWnd, pProfile );
	if( bExists )
	{
		ASSERT( pProfile != NULL );
		VERIFY( m_profile_wnds.RemoveKey(hProfileWnd) );
		if( bRemoveProfileIfLastHWND )
		{
			int nProfileFoundWindowCount = 0;
			for(	POSITION pos = m_profile_wnds.GetStartPosition();
					pos != NULL;
					)
			{
				HWND hWndWalk = NULL;
				CExtCmdProfile * pProfileWalk = NULL;
				m_profile_wnds.GetNextAssoc(
					pos,
					hWndWalk,
					pProfileWalk
					);
				ASSERT( hWndWalk != NULL );
				ASSERT( pProfileWalk != NULL );
				if( pProfileWalk == pProfile )
				{
					nProfileFoundWindowCount++;
					break;
				}
			}
			if( nProfileFoundWindowCount == 0 )
			{
				if( p_bProfileWasRemoved  != NULL )
					*p_bProfileWasRemoved = true;
				CExtSafeString sProfileName( pProfile->m_sName );
				delete pProfile;
				VERIFY( m_profiles.RemoveKey(LPCTSTR(sProfileName)) );
			} // if( nProfileFoundWindowCount == 0 )
		} // if( bRemoveProfileIfLastHWND )
	} // if( bExists )
	m_cs.Unlock();
	return bExists ? true : false;
}

// remove all profile windows
int CExtCmdManager::ProfileWndRemoveAll(
	__EXT_MFC_SAFE_LPCTSTR sProfileName
	)
{
	if(		sProfileName == NULL
		||	_tcslen( sProfileName ) == 0
		)
	{
		ASSERT( FALSE );
		return 0;
	}
	m_cs.Lock();
int nRemovedCount = 0;
CExtCmdProfile * pProfile = NULL;
BOOL bExists = m_profiles.Lookup( sProfileName, (void *&)pProfile );
	if( bExists )
	{
		ASSERT( pProfile != NULL );
		ASSERT( pProfile->m_sName == LPCTSTR(sProfileName) );
		CList < HWND, HWND & > list;
		_ProfileGetWndListImpl( pProfile, list );
		for(	POSITION pos = list.GetHeadPosition();
				pos != NULL;
				)
		{
			HWND hWndWalk = list.GetNext( pos );
			ASSERT( hWndWalk == NULL );
			VERIFY( m_profile_wnds.RemoveKey(hWndWalk) );
			nRemovedCount ++;
		}
		ASSERT( nRemovedCount == list.GetCount() );
	} // if( bExists )
	m_cs.Unlock();
	return nRemovedCount;
}

// get profile window list
void CExtCmdManager::ProfileGetWndList(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	CList < HWND, HWND & > & list
	)
{
	m_cs.Lock();
	_ProfileGetWndListImpl( sProfileName, list );
	m_cs.Unlock();
}

void CExtCmdManager::_ProfileGetWndListImpl(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	CList < HWND, HWND & > & list
	)
{
	list.RemoveAll();
	if(		sProfileName == NULL
		||	_tcslen( sProfileName ) == 0
		)
	{
		ASSERT( FALSE );
		return;
	}
CExtCmdProfile * pProfile = NULL;
BOOL bExists = m_profiles.Lookup( sProfileName, (void *&)pProfile );
	if( ! bExists )
	{
		ASSERT( FALSE );
		return;
	}
	ASSERT( pProfile != NULL );
	ASSERT( pProfile->m_sName == LPCTSTR(sProfileName) );
	_ProfileGetWndListImpl( pProfile, list );
}

void CExtCmdManager::_ProfileGetWndListImpl(
	CExtCmdProfile * pProfile,
	CList < HWND, HWND & > & list
	)
{
	ASSERT( pProfile != NULL );
	ASSERT( ! pProfile->m_sName.IsEmpty() );
	ASSERT( list.GetCount() == 0 );
	for(	POSITION pos = m_profile_wnds.GetStartPosition();
			pos != NULL;
			)
	{
		HWND hWndWalk = NULL;
		CExtCmdProfile * pProfileWalk = NULL;
		m_profile_wnds.GetNextAssoc(
			pos,
			hWndWalk,
			pProfileWalk
			);
		ASSERT( hWndWalk != NULL );
		ASSERT( pProfileWalk != NULL );
		if( pProfileWalk == pProfile )
			list.AddTail( hWndWalk );
	}
}

// remove profile from command manager
bool CExtCmdManager::ProfileDestroy(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	bool bDestroyIfHasWindows // = false
	)
{
	if(		sProfileName == NULL
		||	_tcslen( sProfileName ) == 0
		)
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
CExtCmdProfile * pProfile = NULL;
bool bProfileDestroyed = false;
BOOL bExists = m_profiles.Lookup( sProfileName, (void *&)pProfile );
	if( bExists )
	{
		ASSERT( pProfile != NULL );
		ASSERT( pProfile->m_sName == LPCTSTR(sProfileName) );
		CList < HWND, HWND & > list;
		_ProfileGetWndListImpl( pProfile, list );
		int nWndCount = list.GetCount();
		if( nWndCount > 0 && bDestroyIfHasWindows )
		{
			POSITION pos = list.GetHeadPosition();
			ASSERT( pos != NULL );
			for( ; pos != NULL; )
			{
				HWND hWndWalk = list.GetNext( pos );
				ASSERT( hWndWalk != NULL );
				VERIFY( m_profile_wnds.RemoveKey( hWndWalk ) );
				ASSERT( nWndCount > 0 );
				nWndCount--;
			} // for( ; pos != NULL; )
			ASSERT( nWndCount == 0 );
		} // if( nWndCount > 0 && bDestroyIfHasWindows )
		if( nWndCount == 0 )
		{
			bProfileDestroyed = true;
			CExtSafeString sProfileName2( pProfile->m_sName );
			delete pProfile;
			VERIFY( m_profiles.RemoveKey(LPCTSTR(sProfileName2)) );
		} // if( nWndCount == 0 )
	} // if( bExists )
	m_cs.Unlock();
	return bProfileDestroyed;
}

// rename profile
bool CExtCmdManager::ProfileRename(
	__EXT_MFC_SAFE_LPCTSTR sProfileNameOld,
	__EXT_MFC_SAFE_LPCTSTR sProfileNameNew
	)
{
	if(		sProfileNameOld == NULL
		||	sProfileNameNew == NULL
		||	_tcslen( sProfileNameOld ) == 0
		||	_tcslen( sProfileNameNew ) == 0
		||	_tcscmp( sProfileNameOld, __EXTMFC_DEF_PROFILE_NAME ) == 0
		||	_tcscmp( sProfileNameNew, __EXTMFC_DEF_PROFILE_NAME ) == 0
		)
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bProfileRenamed = false;
CExtCmdProfile * pProfile = NULL;
BOOL bExists = m_profiles.Lookup( sProfileNameOld, (void *&)pProfile );
	if( bExists )
	{
		ASSERT( pProfile != NULL );
		ASSERT( pProfile->m_sName == LPCTSTR(sProfileNameOld) );
		if(	LPVOID(LPCTSTR(sProfileNameOld)) == LPVOID(LPCTSTR(sProfileNameNew)) )
			bProfileRenamed = true;
		else
		{
			CExtCmdProfile * pProfileOther = NULL;
			BOOL bExistsOther = m_profiles.Lookup( sProfileNameNew, (void *&)pProfileOther );
			if( !bExistsOther )
			{
				bProfileRenamed = true;
				CExtSafeString sProfileName = LPCTSTR(sProfileNameOld);
				VERIFY( m_profiles.RemoveKey(LPCTSTR(sProfileName)) );
				pProfile->m_sName = sProfileNameNew;
				m_profiles.SetAt( sProfileNameNew, pProfile );
			} // if( !bExistsOther )
#ifdef _DEBUG
			else
			{
				ASSERT( pProfileOther != NULL );
				ASSERT( pProfileOther->m_sName == LPCTSTR(sProfileNameNew) );
			} // else from if( !bExistsOther )
#endif // _DEBUG
		} // else from if(	LPVOID(LPCTSTR(sProfileNameOld)) == LPVOID(LPCTSTR(sProfileNameNew)) )
	} // if( bExists )
	m_cs.Unlock();
	return bProfileRenamed;
}

// get profile
CExtCmdProfile * CExtCmdManager::ProfileGetPtr(
	__EXT_MFC_SAFE_LPCTSTR sProfileName //  = NULL
	)
{
	if( sProfileName == NULL )
		sProfileName = __EXTMFC_DEF_PROFILE_NAME;
	m_cs.Lock();
CExtCmdProfile * pProfile = NULL;
BOOL bExists = m_profiles.Lookup( sProfileName, (void *&)pProfile );
	if( bExists )
	{
		ASSERT( pProfile != NULL );
		ASSERT( pProfile->m_sName == LPCTSTR(sProfileName) );
	} // if( bExists )
	else
		pProfile = NULL;
	m_cs.Unlock();
	return pProfile;
}

// get profile name for window
__EXT_MFC_SAFE_LPCTSTR CExtCmdManager::ProfileNameFromWnd(
	HWND hWnd
	)
{
	ASSERT( hWnd != NULL );
	if( hWnd == NULL )
		return NULL;
	ASSERT( ::IsWindow(hWnd) );
__EXT_MFC_SAFE_LPCTSTR sProfileName = NULL;
	m_cs.Lock();
	for(	;
			sProfileName == NULL && hWnd != NULL;
			hWnd = GetParent(hWnd) //::GetWindow(hWnd,GW_OWNER)
			)
	{
		CExtCmdProfile * pProfile = NULL;
		BOOL bExists = m_profile_wnds.Lookup( hWnd, pProfile );
		if( !bExists )
			continue;
		ASSERT( pProfile != NULL );
		ASSERT( !pProfile->m_sName.IsEmpty() );
		sProfileName = pProfile->m_sName;
		break;
	}
	m_cs.Unlock();
	return sProfileName;
}

// reset the toolbar/menu command statistics
bool CExtCmdManager::ProfileResetUsageStatistics(
	__EXT_MFC_SAFE_LPCTSTR sProfileName
	)
{
	m_cs.Lock();
bool bRetVal = false;
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile != NULL )
	{
		pProfile->ResetUsageStatistics();
		bRetVal = true;
	} // if( pProfile != NULL )
	m_cs.Unlock();
	return bRetVal;
}

// setup single command
bool CExtCmdManager::CmdSetup(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	const CExtCmdItem & _cmd,
	bool bReplaceOld, // = false // but force set images anywhere if was empty
	bool * pbWasAddedNew // = NULL
	)
{
	if( pbWasAddedNew != NULL )
		*pbWasAddedNew = false;
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bRetVal = pProfile->CmdSetup(_cmd,bReplaceOld,pbWasAddedNew);
	m_cs.Unlock();
	return bRetVal;
}

// remove single command
bool CExtCmdManager::CmdRemove(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	UINT nCmdID,
	bool * pbWasRemoved // = NULL
	)
{
	if( pbWasRemoved != NULL )
		*pbWasRemoved = false;
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bRetVal = pProfile->CmdRemove(nCmdID,pbWasRemoved);
	m_cs.Unlock();
	return bRetVal;
}

bool CExtCmdManager::CmdRemoveByMask(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	DWORD dwMask,
	bool bAllBitsOnly // = false
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
	pProfile->CmdRemoveByMask( dwMask, bAllBitsOnly );
	m_cs.Unlock();
	return true;
}

// alloc command
CExtCmdItem * CExtCmdManager::CmdAllocPtr(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	UINT nCmdID // = 0 // 0 means any free in avail range
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return NULL;
	}
	m_cs.Lock();
CExtCmdItem * pCmdItem = pProfile->CmdAllocPtr(nCmdID);
	m_cs.Unlock();
	return pCmdItem;
}

// get command
CExtCmdItem * CExtCmdManager::CmdGetPtr(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	UINT nCmdID
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return NULL;
	}
	m_cs.Lock();
CExtCmdItem * pCmdItem = pProfile->CmdGetPtr(nCmdID);
	m_cs.Unlock();
	return pCmdItem;
}

// assign icon to command

bool CExtCmdManager::CmdSetIcon(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	UINT nCmdID,
	const CExtCmdIcon * pCmdIcon, // if NULL or empty - remove
	bool bUseCmdIconObject
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bRetVal = pProfile->CmdSetIcon( nCmdID, pCmdIcon, bUseCmdIconObject );
	m_cs.Unlock();
	return bRetVal;
}

bool CExtCmdManager::CmdSetIcon(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	UINT nCmdID,
	const CExtCmdIcon & cmdIcon // if empty - remove
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bRetVal =
		pProfile->CmdSetIcon(
			nCmdID,
			cmdIcon
			);
	m_cs.Unlock();
	return bRetVal;
}

bool CExtCmdManager::CmdSetIcon(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	UINT nCmdID,
	HBITMAP hBitmap, // if NULL - remove
	COLORREF clrTransparent, // = RGB(0,0,0)
	LPCRECT pRectBitmapSrc // = NULL
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bRetVal =
		pProfile->CmdSetIcon(
			nCmdID,
			hBitmap,
			clrTransparent,
			pRectBitmapSrc
			);
	m_cs.Unlock();
	return bRetVal;
}

bool CExtCmdManager::CmdSetIcon(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	UINT nCmdID,
	HICON hIcon, // if NULL - remove
	bool bCopyIcon // = true
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bRetVal =
		pProfile->CmdSetIcon(
			nCmdID,
			hIcon,
			bCopyIcon
			);
	m_cs.Unlock();
	return bRetVal;
}

// get command icon (if command and its icon exist)
CExtCmdIcon * CExtCmdManager::CmdGetIconPtr(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	UINT nCmdID
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return NULL;
	}
	m_cs.Lock();
CExtCmdIcon * pIcon = pProfile->CmdGetIconPtr(nCmdID);
	m_cs.Unlock();
	return pIcon;
}

// is command registered
bool CExtCmdManager::CmdIsRegistered(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	UINT nCmdID
	)
{
	bool bRegistered =
		(CmdGetPtr(sProfileName,nCmdID) != NULL) ?
			true : false;
	return bRegistered;
}

// update commands collection from menu handle
bool CExtCmdManager::UpdateFromMenu(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	HMENU hMenu,
	bool bReplaceOld, // = false
	bool bRecursive, // = true
	bool bLoadTips // = true
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bRetVal =
		pProfile->UpdateFromMenu(
			hMenu, bReplaceOld, bRecursive, bLoadTips );
	m_cs.Unlock();
	return bRetVal;
}

// update commands collection from menu resurce
bool CExtCmdManager::UpdateFromMenu(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	UINT nResourceID,
	bool bReplaceOld, // = false
	bool bLoadTips // = true
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bRetVal =
		pProfile->UpdateFromMenu(
			nResourceID, bReplaceOld, bLoadTips );
	m_cs.Unlock();
	return bRetVal;
}

bool CExtCmdManager::UpdateFromToolBar(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	CToolBar & bar,
	bool bReplaceOld, // = false // but force set images anywhere if was empty
	bool bLoadTips // = true
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bRetVal =
		pProfile->UpdateFromToolBar(
			bar, bReplaceOld, bLoadTips );
	m_cs.Unlock();
	return bRetVal;
}

bool CExtCmdManager::UpdateFromToolBar(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	UINT nResourceID,
	LPUINT * ppCmdArray, // = NULL
	LPINT pCmdCount, // = NULL
	bool bReplaceOld, // = false // but force set images anywhere if was empty
	bool bLoadTips, // = true
	COLORREF clrBmpTransparent // = RGB(192,192,192)
	)
{
	return
		UpdateFromToolBar(
			sProfileName,
			MAKEINTRESOURCE( nResourceID ),
			ppCmdArray,
			pCmdCount,
			bReplaceOld,
			bLoadTips,
			clrBmpTransparent
			);
}

bool CExtCmdManager::UpdateFromToolBar(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	__EXT_MFC_SAFE_LPCTSTR strResourceID,
	LPUINT * ppCmdArray, // = NULL
	LPINT pCmdCount, // = NULL
	bool bReplaceOld, // = false // but force set images anywhere if was empty
	bool bLoadTips, // = true
	COLORREF clrBmpTransparent // = RGB(192,192,192)
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bRetVal =
		pProfile->UpdateFromToolBar(
			strResourceID,
			ppCmdArray,
			pCmdCount,
			bReplaceOld,
			bLoadTips,
			clrBmpTransparent
			);
	m_cs.Unlock();
	return bRetVal;
}


// set list of commands (up to (UINT)0) as basic or non basic
bool CExtCmdManager::SetBasicCommands(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	UINT * pCommands,
	bool bOn // = true
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bRetVal =
		pProfile->SetBasicCommands( pCommands, bOn );
	m_cs.Unlock();
	return bRetVal;
}

#define __REG_LINES_IN_BLOCK	128
#define __REG_LINE_SIZE			16
#define __REG_LINE_FMT			_T("data_0x%08lX")
#define __REG_BLOCK_FMT			_T("block_0x%08lX")
#define __REG_VAR_DATA_SIZE		_T("data_size")
#define __REG_VAR_DATA_CHECK	_T("data_integrity")
#define __REG_VAR_GENERATOR		_T("data_generator")
#define __REG_FMT_GENERATOR		_T("Prof-UIS v. %s registry archiver")

CExtSafeString CExtCmdManager::GetSubSystemRegKeyPath(
	__EXT_MFC_SAFE_LPCTSTR sSubSystemName,
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	__EXT_MFC_SAFE_LPCTSTR sSectionNameCompany, // under HKEY_CURRENT_USER\Software
	__EXT_MFC_SAFE_LPCTSTR sSectionNameProduct // under HKEY_CURRENT_USER\Software\%sSectionNameCompany%
	)
{
	ASSERT( sSubSystemName != NULL );
	ASSERT( sProfileName != NULL );
	ASSERT( sSectionNameCompany != NULL );
	ASSERT( sSectionNameProduct != NULL );
CExtSafeString s;
	s.Format(
		_T("Software\\%s\\%s\\%s\\%s\\%s\\%s"),
		sSectionNameCompany,
		sSectionNameProduct,
		__PROF_UIS_REG_SECTION,
		__PROF_UIS_REG_PROFILES,
		sProfileName,
		sSubSystemName
		);
//	s.Replace(' ','_');
	s.Replace('\r','_');
	s.Replace('\t','_');
	s.Replace('\n','_');
	s.Replace('?','_');
	s.Replace('*','_');
//	s.Replace('.','_'); // (- v.2.23)
//	s.Replace(',','_'); // (- v.2.23)
	return s;
}

bool CExtCmdManager::FileObjToRegistry(
	CFile & _file,
	__EXT_MFC_SAFE_LPCTSTR sRegKeyPath
	)
{
	ASSERT( sRegKeyPath != NULL );
	if( sRegKeyPath == NULL )
		return false;
	CExtRegistry::RegDeleteKey(
		HKEY_CURRENT_USER,
		sRegKeyPath,
		NULL
		);
	_file.Seek( 0, CFile::begin );
DWORD dwLen = (DWORD)_file.GetLength();
CExtRegistry reg;
	if( !reg.Create(
			HKEY_CURRENT_USER,
			sRegKeyPath,
			KEY_ALL_ACCESS
			)
		)
		return false;
	if(	!reg.SaveNumber(
			__REG_VAR_DATA_SIZE,
			dwLen
			)
		)
		return false;
BYTE buffer[__REG_LINE_SIZE];
ULONG nCount, nPortion=0;
CExtIntegrityCheckSum _ExtIntegrityCheckSum;
	for( ; (nCount=_file.Read(&buffer,__REG_LINE_SIZE)) > 0;  )
	{
		CExtSafeString sBlockSubKey;
		ULONG nBlockNo = nPortion/__REG_LINES_IN_BLOCK;
		sBlockSubKey.Format( __REG_BLOCK_FMT, nBlockNo );
		CExtSafeString sRegKeyPath2( sRegKeyPath );
		sRegKeyPath2 += _T('\\');
		sRegKeyPath2 += sBlockSubKey;
		CExtRegistry reg;
		if( !reg.Create(
				HKEY_CURRENT_USER,
				sRegKeyPath2,
				KEY_ALL_ACCESS
				)
			)
			return false;

		CExtSafeString sVarName;
		sVarName.Format(
			__REG_LINE_FMT,
			nPortion++
			);
		if(	!reg.SaveBinary(
				sVarName,
				buffer,
				nCount
				)
			)
			return false;
		_ExtIntegrityCheckSum.Update(
			buffer,
			nCount
			);
	}
USES_CONVERSION;
CExtSafeString sExtIntegrityCheckSum = _ExtIntegrityCheckSum.Final();
	ASSERT( !sExtIntegrityCheckSum.IsEmpty() );
	if(	!reg.SaveString(
			__REG_VAR_DATA_CHECK,
			sExtIntegrityCheckSum
			)
		)
		return false;
	
CExtSafeString sTmpBuffer;
CExtSafeString sGenerator;
	sGenerator.Format(
		__REG_FMT_GENERATOR,
		g_CmdManager.GetVersionString( sTmpBuffer )
		);
	VERIFY(
		reg.SaveString(
			__REG_VAR_GENERATOR,
			sGenerator
			)
		);

	return true;
}

bool CExtCmdManager::FileObjFromRegistry(
	CFile & _file,
	__EXT_MFC_SAFE_LPCTSTR sRegKeyPath
	)
{
	ASSERT( sRegKeyPath != NULL );
	if( sRegKeyPath == NULL )
		return false;
CExtRegistry reg;
	if( !reg.Open(
			HKEY_CURRENT_USER,
			sRegKeyPath,
			KEY_READ
			)
		)
		return false;
DWORD dwLen = 0;
	if(	!reg.LoadNumber(
			__REG_VAR_DATA_SIZE,
			&dwLen
			)
		)
		return false;
	if( dwLen == 0 )
		return true;
BYTE buffer[__REG_LINE_SIZE];
ULONG nCount = __REG_LINE_SIZE, nPortion = 0;
DWORD dwLoaded = 0;
CExtIntegrityCheckSum _ExtIntegrityCheckSum;
	for( ; true;  )
	{
		CExtSafeString sBlockSubKey;
		ULONG nBlockNo = nPortion/__REG_LINES_IN_BLOCK;
		sBlockSubKey.Format( __REG_BLOCK_FMT, nBlockNo );
		CExtSafeString sRegKeyPath2( sRegKeyPath );
		sRegKeyPath2 += _T('\\');
		sRegKeyPath2 += sBlockSubKey;
		CExtRegistry reg;
		if( !reg.Open(
				HKEY_CURRENT_USER,
				sRegKeyPath2,
				KEY_READ
				)
			)
			return false;
	
		CExtSafeString sVarName;
		sVarName.Format(
			__REG_LINE_FMT,
			nPortion++
			);
		if( dwLen-dwLoaded < __REG_LINE_SIZE )
			nCount = dwLen-dwLoaded;
		ASSERT( nCount > 0 && nCount <= __REG_LINE_SIZE );
		if(	!reg.LoadBinary(
				sVarName,
				buffer,
				nCount
				)
			)
			return false;
		dwLoaded += nCount;
		ASSERT( dwLoaded <= dwLen );

		_ExtIntegrityCheckSum.Update(
			buffer,
			nCount
			);
		_file.Write(
			buffer,
			nCount
			);

		if( dwLoaded == dwLen )
			break;
	}
USES_CONVERSION;
CExtSafeString sExtIntegrityCheckSum = _ExtIntegrityCheckSum.Final();
	ASSERT( !sExtIntegrityCheckSum.IsEmpty() );

CExtSafeString sExtIntegrityCheckSumA;
int nSz = sExtIntegrityCheckSum.GetLength() + 1;
	if(	!reg.LoadString(
			__REG_VAR_DATA_CHECK,
			sExtIntegrityCheckSumA.GetBuffer( nSz ),
			nSz
			)
		)
	{
		sExtIntegrityCheckSumA.ReleaseBuffer();
		return false;
	}
	sExtIntegrityCheckSumA.ReleaseBuffer();

	if( sExtIntegrityCheckSumA != sExtIntegrityCheckSum )
	{
		ASSERT( FALSE );
		return false;
	}

	_file.Seek( 0, CFile::begin );

	return true;
}

// save/load command manager state
bool CExtCmdManager::SerializeState(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	__EXT_MFC_SAFE_LPCTSTR sSectionNameCompany, // under HKEY_CURRENT_USER\Software
	__EXT_MFC_SAFE_LPCTSTR sSectionNameProduct, // under HKEY_CURRENT_USER\Software\%sSectionNameCompany%
	bool bSave
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bRetVal =
		pProfile->SerializeState(
			sSectionNameCompany,
			sSectionNameProduct,
			bSave
			);
	m_cs.Unlock();
	return bRetVal;
}

bool CExtCmdManager::SerializeState(
	__EXT_MFC_SAFE_LPCTSTR sProfileName,
	CArchive & ar
	)
{
CExtCmdProfile * pProfile = ProfileGetPtr( sProfileName );
	if( pProfile == NULL )
	{
		ASSERT( FALSE );
		return false;
	}
	m_cs.Lock();
bool bRetVal =
		pProfile->SerializeState( ar );
	m_cs.Unlock();
	return bRetVal;
}

void CExtCmdManager::OnSysColorChange()
{
	m_cs.Lock();
POSITION pos = m_profiles.GetStartPosition();
	for( ; pos != NULL; )
	{
		CExtSafeString sProfileName;
		CExtCmdProfile * pProfile = NULL;
		m_profiles.GetNextAssoc( pos, sProfileName, (void *&)pProfile );
		ASSERT( pProfile != NULL );
		pProfile->OnSysColorChange();
	} // for( ; pos != NULL; )
	m_cs.Unlock();
}

void CExtCmdManager::OnSettingChange(
	UINT uFlags,
	__EXT_MFC_SAFE_LPCTSTR lpszSection
	)
{
	m_cs.Lock();
POSITION pos = m_profiles.GetStartPosition();
	for( ; pos != NULL; )
	{
		CExtSafeString sProfileName;
		CExtCmdProfile * pProfile = NULL;
		m_profiles.GetNextAssoc( pos, sProfileName, (void *&)pProfile );
		ASSERT( pProfile != NULL );
		pProfile->OnSettingChange( uFlags, lpszSection );
	} // for( ; pos != NULL; )
	m_cs.Unlock();
}

void CExtCmdManager::OnDisplayChange(
	INT nDepthBPP,
	CPoint ptSizes
	)
{
	m_cs.Lock();
POSITION pos = m_profiles.GetStartPosition();
	for( ; pos != NULL; )
	{
		CExtSafeString sProfileName;
		CExtCmdProfile * pProfile = NULL;
		m_profiles.GetNextAssoc( pos, sProfileName, (void *&)pProfile );
		ASSERT( pProfile != NULL );
		pProfile->OnDisplayChange( nDepthBPP, ptSizes );
	} // for( ; pos != NULL; )
	m_cs.Unlock();
}

void CExtCmdManager::OnThemeChanged(
	WPARAM wParam,
	LPARAM lParam
	)
{
	m_cs.Lock();
POSITION pos = m_profiles.GetStartPosition();
	for( ; pos != NULL; )
	{
		CExtSafeString sProfileName;
		CExtCmdProfile * pProfile = NULL;
		m_profiles.GetNextAssoc( pos, sProfileName, (void *&)pProfile );
		ASSERT( pProfile != NULL );
		pProfile->OnThemeChanged( wParam, lParam );
	} // for( ; pos != NULL; )
	m_cs.Unlock();
}